<?PHP
// vim: set expandtab tabstop=4 shiftwidth=4: 
// +----------------------------------------------------------------------+
// | SAPID: XML Sapiens Engine Demonstrator                               |
// +----------------------------------------------------------------------+
// | Author:  Max Baryshnikov aka Mephius <mb@rg.by>	                  |
// | Copyright (c) 2004 Max Baryshnikov                                   |
// | http://sapid.sourceforge.net	                                      |
// +----------------------------------------------------------------------+
// | This source file is free software; you can redistribute it and/or    |
// | modify it under the terms of the GNU Lesser General Public           |
// | License as published by the Free Software Foundation; either         |
// | version 2.1 of the License, or (at your option) any later version.   |
// |                                                                      |
// | This source file is distributed in the hope that it will be useful,  |
// | but WITHOUT ANY WARRANTY; without even the implied warranty of       |
// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU    |
// | Lesser General Public License for more details.                      |
// +----------------------------------------------------------------------+
// Release: 08.09.04 (dd/mm/yy)

include(realpath("../../etc/rc.conf.php"));

//@session_id($_GET["sid"]);
//@session_start();
//if(!isset($_SESSION["user"]["LOGIN"])) die();
function d($var=false)
{
	echo '<pre style="font-size: 10px;  color: Maroon; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;">';
	print_r($var);
	echo '</pre>';
}


function sapi_start($parser, $name, $attribs){
	global $graph;

	switch ($name){
		case "SAPI:WHEN":
		$graph->element["count"]++;
		if($attribs["TITLE"]) $graph->comment_stack[$graph->element["count"]]=$attribs["TITLE"]; else
		if($attribs["EXP"]) $graph->comment_stack[$graph->element["count"]]=($attribs["EXP"]=="1"?"true":($attribs["EXP"]=="0"?"false":$attribs["EXP"]));
		$graph->decision();
		break;
		case "SAPI:EXP":
		$graph->element["name"]="exp";
		break;
		case "SAPI:FOR-EACH":
		$graph->element["count"]++;
		$graph->comment_stack[$graph->element["count"]]=($attribs["TITLE"]?$attribs["TITLE"]:$attribs["SELECT"]);
		$graph->cycle();
		break;
		case "SAPI:CODE":
		if($attribs["TITLE"]) $graph->element["comment"]=$attribs["TITLE"];
		$graph->element["name"]="code";
		$graph->element["count"]++;
		$graph->code();
		break;
		default:
		$graph->element["name"]="";
		break;

	}
}

function sapi_end($parser, $name){
	global $graph;
	switch ($name){
		case "SAPI:WHEN": $graph->close_block("decision"); break;
		case "SAPI:CODE": $graph->element["comment"]=""; break;
		case "SAPI:FOR-EACH": $graph->close_block("cycle"); break;
	}


}

function sapi_data($parser, $data){
	global $graph;
	if($graph->element["name"]=="code" and $graph->element["comment"]!="") {
		$graph->comment_stack[$graph->element["count"]]=$graph->element["comment"];
	}else{
		if (trim($data)!="" and ($graph->element["name"]=="code" or $graph->element["name"]=="exp")) {
			$graph->comment_stack[$graph->element["count"]].=htmlentities($data) . "<br />";
		}
	}
}


class algraph {
	var $width;
	var $height;
	var $im;
	var $bg;
	var $color;
	var $pallette=array();
	var $x=10;
	var $y=12;
	var $stack=array();
	var $comment_stack=array();
	var $map="";
	var $element=array();


	function algraph($width, $height){
		$this->width=$width;
		$this->height=$height;
		$this->im=imagecreate($this->width, $this->height);
		$this->bg=imagecolorallocate($this->im, 237, 237, 237);
		$this->init_pallette();
		$this->color=$this->pallette["black"];
		imagefill($this->im, 0, 0, $this->bg);
		$this->header();
	}

	function init_pallette(){
		$this->pallette=array(
		"blue"=>imagecolorallocate($this->im, 0, 0, 255),
		"green"=>imagecolorallocate($this->im, 40, 154, 31),
		"red"=>imagecolorallocate($this->im, 208, 28, 28),
		"black"=>imagecolorallocate($this->im, 0, 0, 0),
		);
	}
	function moveto($x, $y){
		$this->x=$x;
		$this->y=$y;
	}

	function lineto($x, $y){
		imageline($this->im, $this->x, $this->y, $x, $y, $this->color);
		$this->x=$x;
		$this->y=$y;
	}

	function text($x, $y, $text, $font=2){
		$arr=explode("\r\n", $text);
		if (count($arr)>1) {
			for($i=0; $i<count($arr); $i++){
				imagestring($this->im, $font, $x, $y+($i*10), $arr[$i], $this->color);
			}
		}else imagestring($this->im, $font, $x, $y, $text, $this->color);
	}

	function arrow($direction="down"){
		$this->color=$this->pallette["black"];
		switch ($direction){
			case "down":
			$polygon=array($this->x, $this->y, $this->x-2, $this->y-5, $this->x+2, $this->y-5);
			imagepolygon($this->im, $polygon, 3, $this->color);
			break;
			case "left":
			$polygon=array($this->x, $this->y, $this->x+5, $this->y-2, $this->x+5, $this->y+2);
			imagepolygon($this->im, $polygon, 3, $this->color);
			break;
			case "top":
			$polygon=array($this->x, $this->y, $this->x-2, $this->y+5, $this->x+2, $this->y+5);
			imagepolygon($this->im, $polygon, 3, $this->color);
			break;
		}
	}

	function decision(){
		$this->fit(50, 60);
		$this->color=$this->pallette["black"];
		$this->lineto($this->x, $this->y+20);
		$this->arrow();
		array_push($this->stack, array("x"=>$this->x, "y"=>$this->y+20));
		$this->map.='<area alt="" shape="poly" coords="'.$this->x.','.$this->y.','.($this->x-20).','.($this->y+10).','.($this->x).','.($this->y+20).','.($this->x+20).','.($this->y+10).'" href="#" onClick="return display('.$this->element["count"].', event);">'."\r\n";
		$polygon=array($this->x, $this->y, $this->x-20, $this->y+10, $this->x, $this->y+20, $this->x+20, $this->y+10);
		$this->color=$this->pallette["green"];
		imagepolygon($this->im, $polygon, 4, $this->color);
		$this->text($this->x-10, $this->y+6, "if()", 1);
		$this->moveto($this->x+20, $this->y+10);
		$this->text($this->x+3, $this->y-15, "true");
		$this->color=$this->pallette["red"];
		$this->text($this->x-55, $this->y+10, "false");

		$this->color=$this->pallette["black"];
		$this->lineto($this->x+30, $this->y);
	}

	function cycle(){
		$this->fit(50, 50);
		$this->color=$this->pallette["black"];
		$this->lineto($this->x, $this->y+20);
		$this->arrow();
		array_push($this->stack, array("x"=>$this->x, "y"=>$this->y+20));
		$this->map.='<area alt="" shape="poly" coords="'.$this->x.','.$this->y.','.($this->x-10).','.$this->y.','.($this->x-20).','.($this->y+10).','.($this->x-10).','.($this->y+20).','.($this->x+10).','.($this->y+20).','.($this->x+20).','.($this->y+10).','.($this->x+10).','.$this->y.'" href="#" onClick="return display('.$this->element["count"].', event);">'."\r\n";
		$polygon=array($this->x, $this->y, $this->x-10, $this->y, $this->x-20, $this->y+10, $this->x-10, $this->y+20, $this->x+10, $this->y+20, $this->x+20, $this->y+10, $this->x+10, $this->y);
		$this->color=$this->pallette["red"];
		$this->text($this->x-10, $this->y+5, "for()", 1);
		imagepolygon($this->im, $polygon, 7, $this->color);
		$this->color=$this->pallette["black"];

		$this->moveto($this->x+20, $this->y+10);
		$this->lineto($this->x+30, $this->y);
	}

	function code(){
		$this->fit(60, 30);
		$this->color=$this->pallette["black"];
		$this->lineto($this->x, $this->y+20);
		$this->arrow();
		$this->map.='<area alt="" shape="poly" coords="'.($this->x-20).','.$this->y.','.($this->x-20).','.($this->y+20).','.($this->x+20).','.($this->y+20).','.($this->x+20).','.$this->y.'" href="#" onClick="return display('.$this->element["count"].', event);">'."\r\n";
		$polygon=array($this->x-20, $this->y, $this->x-20, $this->y+20, $this->x+20, $this->y+20, $this->x+20, $this->y);
		$this->color=$this->pallette["blue"];
		imagepolygon($this->im, $polygon, 4, $this->color);

		$this->text($this->x-15, $this->y+6, "<code>", 1);
		$this->color=$this->pallette["black"];
		$this->moveto($this->x, $this->y+20);
		$this->fit(30, 50);
		$this->lineto($this->x, $this->y+20);
	}

	function close_block($shape="decision"){
		$this->fit();
		switch ($shape){
			case "decision":
			$coords=array_pop($this->stack);
			$dx=$coords["x"]-$this->x;
			$dy=$coords["y"]-$this->y;

			$this->lineto($this->x+$dx, $this->y);
			$c=array("x"=>$this->x, "y"=>$this->y);
			$this->lineto($this->x, $this->y+$dy);
			$this->moveto($c["x"], $c["y"]);
			$this->arrow();
			$this->arrow("left");
			//$this->lineto($this->x, $this->y+20);
			break;
			case "cycle":
			$coords=array_pop($this->stack);
			$dx=$coords["x"]-$this->x;
			$dy=$coords["y"]-$this->y;

			$this->lineto($this->x+$dx, $this->y);
			$c=array("x"=>$this->x, "y"=>$this->y);
			$this->lineto($this->x, $this->y+$dy);
			$this->arrow("top");
			$this->moveto($this->x-20, $this->y-10);
			$this->lineto($this->x-10, $this->y);
			$this->lineto($this->x, $c["y"]);

			break;
		}

	}

	function fit($dx=30, $dy=30){
		$new_width=$this->width;
		$new_height=$this->height;
		if($this->x+$dx >= imagesx($this->im)) $new_width+=$dx;
		if($this->y+$dx >= imagesy($this->im)) $new_height+=$dy;
		if($new_width!=imagesx($this->im) or $new_height!=imagesy($this->im)){
			$img = imagecreate($new_width, $new_height);
			imagecopy($img, $this->im, 0, 0, 0, 0, imagesx($this->im), imagesy($this->im));
			imagedestroy($this->im);
			$this->im=$img;
			$this->init_pallette();
			$this->width=$new_width;
			$this->height=$new_height;
			$this->fit($dx, $dy);
		}

	}

	function header(){
		$this->moveto(10,20);
		$this->lineto(100, 20);
		$this->moveto(50, 20);
		$this->text(10, 8, "Enter");
	}


	function footer(){
		$this->lineto($this->x, $this->y+20);
		$this->arrow();
		$this->lineto($this->x-10, $this->y);
		$this->lineto($this->x+110, $this->y);
		$this->text($this->x-90, $this->y-12, "Exit");
		$stamp=imagecreatefrompng("images/stamp.png");
		imagecopymerge($this->im, $stamp, imagesx($this->im)-105, 10, 0, 0, 100, 95, 50);
		imagedestroy($stamp);
	}


	function print_info($info){
		//		$d=imagettfbbox($this->fontsize, 0, realpath($this->font), $info);
		$this->text(imagesx($this->im)-145, 8, $info, 1);
		//imagestringup($this->im, 2, imagesx($this->im)-15, imagesy($this->im)-10, "Created with SAPID.", $this->pallette["blue"]);

	}

	function display($type="png"){
		$this->width=imagesx($this->im);
		$this->height=imagesy($this->im);
		$this->footer();
		//header("Content-type: image/" , $type);
		switch ($type){
			case "png": imagepng($this->im, "cache/" . ($_GET["name"]?$_GET["name"]:$GLOBALS["name"]) . ".png"); break;
			case "jpeg": imagejpeg($this->im, "cache/" . ($_GET["name"]?$_GET["name"]:$GLOBALS["name"]) . ".jpg"); break;
		}
		imagedestroy($this->im);

	}
}

$name=($_GET["name"]?$_GET["name"]:"guestbook");
$file=$root_path . "usr/xml/ddc/" . $name . "";

$fp=fopen($file, "r");
$size=filesize($file);
$ddc_body=fread($fp, $size);
$ddc_body=preg_replace("/<sapi:code(.*)>/isU", "<sapi:code\\1><![CDATA[", $ddc_body);
$ddc_body=str_replace("</sapi:code>", "]]></sapi:code>", $ddc_body);



$graph = new algraph(300, 300);

preg_match("/<sapi:author>\s{0,}<sapi:name>(.*)<\/sapi:name>\s{0,}<sapi:email>([a-zA-z_\.]+@[a-zA-z_\.]+[a-zA-Z]+)<\/sapi:email>\s{0,}<sapi:url>([a-zA-Z\_\.]+)<\/sapi:url>\s{0,}<\/sapi:author>/", $ddc_body, $matches);
$author="Author: ".$matches[1]."\r\nEmail: " . $matches[2] . "\r\nURL: ".$matches[3] . "\r\n";
preg_match("/<sapi:comments>(.*?)<\/sapi:comments>/s", $ddc_body, $matches);
$description ="DDC: " . $name . "\r\n" . $author . "\r\n" . wordwrap($matches[1], 20, "\r\n");


$sp=xml_parser_create();
xml_set_element_handler($sp, 'sapi_start', 'sapi_end');
xml_set_character_data_handler($sp, 'sapi_data');
xml_parser_set_option($sp, XML_OPTION_SKIP_WHITE, 1);

if(!xml_parse($sp, $ddc_body)){
	$Eline  = xml_get_current_line_number($sp);
	$Ecode  = xml_get_error_code($sp);
	$Estr   = xml_error_string($Ecode);
	d($Eline);
	d($Ecode);
	d($Estr);
}
$graph->print_info($description);
$graph->display("png");

echo '
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
	<title>DDC alorythm viewer - '.$_GET["name"].'</title>
	<link rel="stylesheet" type="text/css" href="'.$http_path.'usr/system/light.css" />
<script type="text/javascript">
var px='.($graph->width+50).';
var py='.(($graph->height<=680?$graph->height:640)+50).'; 
';


if(is_array($graph->comment_stack)){
	echo '
var comments = new Array();
var ind=false;
	';
	foreach ($graph->comment_stack as $key=>$value) {
		echo 'comments['.$key.']="'.substr(addslashes(trim(preg_replace("/(\\r)?\\n/", "<br />", $value))), 0, 1000).(strlen(addslashes($value))>1000?" ... ":"").'";'."\r\n";
	}
}
echo '

	function display(index, ev){
		if(ev.x) {
			var x=window.event.x+document.body.scrollLeft;
			var y=window.event.y+document.body.scrollTop;
		} else {
			var x=ev.pageX;
			var y=ev.pageY;
		}

		if(document.getElementById(\'helper\').style.display=="block" && ind==index) document.getElementById(\'helper\').style.display="none"; else {
			ind=index;
			document.getElementById(\'helper\').style.left=x+3+"px";
			document.getElementById(\'helper\').style.top=y+3+"px";

			
			
			
			document.getElementById(\'helper\').innerHTML=comments[index];
			document.getElementById(\'helper\').style.display="block";
		}
		return false;
	}
	
	function hide(){
		ind=false;
		document.getElementById(\'helper\').style.display="none";
	}

	</script>

</head>

<body onload="resizeTo(px, py);">
<div id="helper" onclick="hide()" style="position: absolute; border: 1px solid gray; background-color: #dfdfdf; padding: 5px; display: none; font-size: 10px;"></div>
<img id="graph" src="'.$http_path.'usr/system/cache/'.$name.'.png" usemap="#map" border="0" style="border: 1px solid gray; margin: 10px;" align="left" />
<map name="map">
'.$graph->map.'</map>
</body>
</html>
';
?>